﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic.Links;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Analytics.UI.Common.Wizard;
using DiscoveryLogic.Common.Utilities;
using MessageBox=System.Windows.MessageBox;
using UserControl=System.Windows.Controls.UserControl;

namespace DiscoveryLogic.Analytics.Modules.LinkRules
{
    /// <summary>
    /// Interaction logic for LinkRuleDistanceCalculator.xaml
    /// </summary>
    public partial class LinkRuleDistanceCalculator : UserControl, IWizardPageBase 
    {
        private Wizard _Owner;
        
        public LinkRuleDistanceCalculator()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.cboCalculator.Items.Clear();
            Assembly assembly = typeof(IEntityLinker).Assembly;
            Type[] types = assembly.GetTypes();
            foreach (Type type in types)
            {
                if (type.GetInterface(typeof(IEntityLinker).FullName) != null)
                {
                    this.cboCalculator.Items.Add(type.FullName);
                }
            }

            EntityRelationRule rule =
                (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];

            if (rule.EntityLinkerName != null)
                this.cboCalculator.Text = rule.EntityLinkerName;
            this.ckDirectional.IsChecked = rule.Directional;
            this.ckAllowLoopback.IsChecked = rule.AllowLoopBack;
        }

        private void cboCalculator_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if(!this.IsInitialized)
                return;

            EntityRelationRule rule =
                (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];

            if(this.cboCalculator.SelectedIndex>=0 &&
                rule.SrcEntityType != null &&
                rule.TgtEntityType != null)
            {
                PropertyInfo[] srcProps = EntityTypeUtil.GetProperties(rule.SrcEntityType);
                PropertyInfo[] tgtProps = EntityTypeUtil.GetProperties(rule.TgtEntityType);
                
                Assembly assembly = typeof(IEntityLinker).Assembly;
                Type calcType = assembly.GetType(this.cboCalculator.SelectedItem.ToString());
                IEntityLinker calc =
                    (IEntityLinker)
                    Activator.CreateInstance(calcType);
                this.dvArgBindings.Rows.Clear();
                if(calc !=null && calc.ArgNames !=null)
                {
                    foreach(string argName in calc.ArgNames)
                    {
                        DataGridViewRow dr = new DataGridViewRow();
                        DataGridViewTextBoxCell cellArg=new DataGridViewTextBoxCell();
                        cellArg.Value = argName;
                        dr.Cells.Add(cellArg);

                        DataGridViewComboBoxCell cellSrcFields=new DataGridViewComboBoxCell();
                        foreach(PropertyInfo srcProp in srcProps)
                        {
                            if(srcProp.CanWrite && srcProp.CanRead)
                            {
                                cellSrcFields.Items.Add(srcProp.Name);
                            }
                            if(rule.LinkCalcArgumentMappings !=null && 
                                rule.LinkCalcArgumentMappings.ContainsKey(argName) && 
                                rule.LinkCalcArgumentMappings[argName].FromSrcEntity)
                            {
                                cellSrcFields.Value = rule.LinkCalcArgumentMappings[argName].PropertyName;
                            }
                        }
                        dr.Cells.Add(cellSrcFields);

                        DataGridViewComboBoxCell cellTgtFields=new DataGridViewComboBoxCell();
                        foreach(PropertyInfo tgtProp in tgtProps)
                        {
                            if(tgtProp.CanRead && tgtProp.CanWrite)
                            {
                                cellTgtFields.Items.Add(tgtProp.Name);
                            }
                            if(rule.LinkCalcArgumentMappings !=null && 
                                rule.LinkCalcArgumentMappings.ContainsKey(argName) && 
                                rule.LinkCalcArgumentMappings[argName].FromTgtEntity)
                            {
                                cellTgtFields.Value = rule.LinkCalcArgumentMappings[argName].PropertyName;
                            }
                        }
                        dr.Cells.Add(cellTgtFields);

                        this.dvArgBindings.Rows.Add(dr);
                    }
                }
            }
        }

        private void ckAllowLoopback_Checked(object sender, RoutedEventArgs e)
        {
            if (this.IsInitialized)
            {
                if (this.ckAllowLoopback.IsChecked.Value)
                    this.rngThreshold.IsEnabled = true;
                else
                    this.rngThreshold.IsEnabled = false;
            }
        }

        #region Implementation of IWizardPageBase

        public event OnBeforeMoveToNext BeforeMoveToNext;
        public event OnBeforeDisplay BeforeDisplay;
        private IWizardPageBase _PrevPage;
        public IWizardPageBase PrevPage
        {
            get
            {
                return _PrevPage;
            }
            set
            {
                _PrevPage = value;
            }
        }

        private IWizardPageBase _NextPage;
        public IWizardPageBase NextPage
        {
            get
            {
                return _NextPage;
            }
            set
            {
                _NextPage = value;
            }
        }

        private string _Title = "Link Calculator";
        public string Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
            }
        }

        private string _Desc = "Specify how argument should bind to entity fields";
        public string Description
        {
            get
            {
                return _Desc;
            }
            set
            {
                _Desc = value;
            }
        }

        public void Init(Wizard owner)
        {
            this._Owner = owner;
        }

        public bool MoveNextPage()
        {
            if(this.cboCalculator.SelectedIndex<0)
                return false;

            try
            {
                EntityRelationRule rule =
                    (EntityRelationRule) this._Owner.SharedVariables["LinkRule"];
                rule.LinkType = LinkType.Citation;
                rule.Directional = this.ckDirectional.IsChecked.Value;
                rule.EntityLinkerName = this.cboCalculator.Text;
                rule.LinkDistanceThreshold = this.rngThreshold.Value;
                rule.HopDampFactor = this.rngHopDampFactor.Value;
                rule.AllowLoopBack = this.ckAllowLoopback.IsChecked.Value;
                rule.LinkCalcArgumentMappings = new Dictionary<string, ArgumentFieldBinding>();
                foreach (DataGridViewRow dr in this.dvArgBindings.Rows)
                {
                    if (!dr.IsNewRow && dr.Cells[0].Value != null &&
                        (dr.Cells[1].Value != null || dr.Cells[2].Value != null))
                    {
                        string argName = dr.Cells[0].Value.ToString();
                        ArgumentFieldBinding argBinding = new ArgumentFieldBinding();
                        argBinding.ArgumentName = argName;

                        if (dr.Cells[1].Value != null && dr.Cells[1].Value.ToString().Length > 0)
                        {
                            argBinding.FromSrcEntity = true;
                            argBinding.FromTgtEntity = false;
                            argBinding.PropertyName = dr.Cells[1].Value.ToString();
                        }
                        else
                        {
                            argBinding.FromSrcEntity = false;
                            argBinding.FromTgtEntity = true;
                            argBinding.PropertyName = dr.Cells[2].Value.ToString();
                        }
                        rule.LinkCalcArgumentMappings.Add(argName, argBinding);
                    }
                }

                if(this.BeforeMoveToNext !=null)
                    this.BeforeMoveToNext(new WizardPageNavigationEventArgs(this._Owner, false));
                return true;
            }
            catch(Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                MessageBox.Show(ex.Message);
                return false;
            }
        }
        #endregion

        private void rngThreshold_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if(this.IsInitialized)
            {
                this.lblThresholdValue.Content = e.NewValue.ToString();
            }
        }

        private void rngHopDampFactor_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this.IsInitialized)
            {
                this.lblHopDampValue.Content = e.NewValue.ToString();
            }
        }
    }
}
